import { Prefab, SpriteFrame, Node, Light } from 'cc'
import Singleton from '../Base/Singleton'
import { IBullet, IClientInput, InputTypeEnum, IRoom, IState, toFixed } from '../Common'
import { ActorManager } from '../Entity/Actor/ActorManager'
import { BulletManager } from '../Entity/Bullet/BulletManager'
import { EventEnum } from '../Enum'
import { JoyStickManager } from '../UI/JoyStickManager'
import { randomBySeed } from '../Utils'
import EventManager from './EventManager'

// 数据集换中心
const ACTOR_SPEED = 100 // 角色速度
const BULLET_SPEED = 600 // 子弹速度
const MAP_WIDTH = 960 // 地图宽
const MAP_HEIGHT = 640 // 地图高

const ACTOR_RADIUS = 50 // 角色碰撞半径
const BULLET_RADIUS = 10 // 子弹碰撞半径

const BULLET_DAMAGE = 5 // 子弹伤害

export default class DataManager extends Singleton {
  static get Instance() {
    return super.GetInstance<DataManager>()
  }
  /*---------------登录---------------*/
  // 当前角色id
  playerID = 1
  /*---------------大厅---------------*/
  // 当前房间
  roomInfo: IRoom
  /*---------------游戏战场---------------*/
  // 舞台模块
  stage: Node
  // 遥控杆模块实例
  jm: JoyStickManager

  // 地图中角色控制模块集合
  actorMap: Map<number, ActorManager> = new Map()
  // 地图中子弹控制模块集合
  bulletMap: Map<number, BulletManager> = new Map()
  // 模型集合
  prefabMap: Map<string, Prefab> = new Map()
  // 纹理集合
  textureMap: Map<string, SpriteFrame[]> = new Map()

  // 死亡人数
  deadNum = 0
  // 渲染帧id
  frameID = 0
  // 上次同步数据
  lastState: IState
  // 同步数据
  state: IState = {
    // 地图中角色信息集合
    actors: [
      // {
      //   id: 1,
      //   hp: 100,
      //   type: EntityTypeEnum.Actor1,
      //   weaponType: EntityTypeEnum.Weapon1,
      //   bulletType: EntityTypeEnum.Bullet2,
      //   position: { x: -150, y: -150 },
      //   direction: { x: 1, y: 0 },
      // },
      // {
      //   id: 2,
      //   hp: 100,
      //   type: EntityTypeEnum.Actor1,
      //   weaponType: EntityTypeEnum.Weapon1,
      //   bulletType: EntityTypeEnum.Bullet2,
      //   position: { x: 150, y: 150 },
      //   direction: { x: -1, y: 0 },
      // },
    ],
    // 子弹集合
    bullets: [],
    // 子弹id
    nextBulletID: 1,
    // 随机数种子
    seed: 1,
  }

  reset() {
    this.deadNum = 0
    this.frameID = 0
    this.stage = null
    this.jm = null
    this.actorMap.clear()
    this.bulletMap.clear()
    this.prefabMap.clear()
    this.textureMap.clear()
  }
  // 处理用户输入指令
  applyInput(input: IClientInput) {
    switch (input.type) {
      // 移动指令
      case InputTypeEnum.ActorMove: {
        const {
          id,
          dt,
          direction: { x, y },
        } = input
        const actor = this.state.actors.find(e => e.id == id)
        if (!actor) return
        actor.direction = { x, y }
        actor.position.x = toFixed(actor.position.x + x * dt * ACTOR_SPEED)
        actor.position.y = toFixed(actor.position.y + y * dt * ACTOR_SPEED)
        break
      }
      // 射击指令
      case InputTypeEnum.WeaponShoot: {
        // 构造子弹
        const bullet: IBullet = {
          id: this.state.nextBulletID++,
          ...input,
          type: this.actorMap.get(input.owner).bulletType,
        }
        EventManager.Instance.emit(EventEnum.BulletBorn, input.owner)
        this.state.bullets.unshift(bullet)
        break
      }
      // 时间流逝-物理效果(子弹移动，爆炸，血量扣减)
      case InputTypeEnum.TimePast: {
        const { dt } = input
        const { bullets, actors } = this.state

        // 遍历子弹
        for (let i = 0; i < bullets.length; i++) {
          const bullet = bullets[i]

          // 子弹碰撞人物效果
          for (let j = 0; j < actors.length; j++) {
            const actor = actors[j]
            // 计算子弹与玩家中心距离
            const distance = Math.sqrt((actor.position.x - bullet.position.x) ** 2 + (actor.position.y - bullet.position.y) ** 2)
            // 子弹与玩家半径之和
            const entity = BULLET_RADIUS + ACTOR_RADIUS
            // 射击命中爆炸并销毁
            if (distance <= entity) {
              const random = randomBySeed(this.state.seed)
              this.state.seed = random
              const num = random / 233280 // 获得0-1间的数
              // 伤害计算
              const damage = num > 0.5 ? BULLET_DAMAGE * 2 : BULLET_DAMAGE
              EventManager.Instance.emit(EventEnum.ExplosionBorn, bullet.id, {
                x: toFixed((bullet.position.x + actor.position.x) / 2),
                y: toFixed((bullet.position.y + actor.position.y) / 2),
              })
              actor.hp -= damage
              bullets.splice(i, 1)
              break
            }
          }

          // 超出地图爆炸并销毁
          if (Math.abs(bullet.position.x) > MAP_WIDTH / 2 || Math.abs(bullet.position.y) > MAP_HEIGHT / 2) {
            EventManager.Instance.emit(EventEnum.ExplosionBorn, bullet.id, bullet.position)
            bullets.splice(i, 1)
            break
          }
        }

        // 子弹位置变更
        for (const bullet of bullets) {
          bullet.position.x += toFixed(bullet.direction.x * dt * BULLET_SPEED)
          bullet.position.y += toFixed(bullet.direction.y * dt * BULLET_SPEED)
        }
        break
      }
      default:
        break
    }
  }
}
